import 'dart:async';
import 'dart:io';

import 'package:audio_output_device_new/audio_output_device_new.dart';
import 'package:flutter/foundation.dart';

import '../bean/bean.dart';
import '../util/util.dart';

mixin AudioOutputDeviceHandler{

  final AudioOutputDeviceNew _audioOutputDevice = AudioOutputDeviceNew();

  /// 原始数据
  Set<AudioDevice> _audioDevices = {};
  /// 转化后数据
  List<BleDevice> _a2dpDevices = [];

  bool _hasInit = false;
  StreamSubscription? _classicDeviceDisconnectedSubs;

  final StreamController<List<BleDevice>> _headsetsController = StreamController<List<BleDevice>>.broadcast();
  late final Stream<List<BleDevice>> _headsets;

  /// 当前的 ble 耳机设备列表
  Stream<List<BleDevice>> get headsets {
    /// assert only works in debug mode
    assert(_hasInit, "hasn't init yet");
    return _headsets;
  }



  Future<void> initAudioOutputDeviceHandler({bool enableLog = false}) async{
    if(!_hasInit){
      _hasInit = true;

      _headsets = _headsetsController.stream;

      if(Platform.isAndroid){
        _classicDeviceDisconnectedSubs = _audioOutputDevice
            .classicDeviceDisconnected.listen(_onClassicDeviceDisconnected);
      }


      Log.enableLog = enableLog;
      await _audioOutputDevice.initAudioSession(
          onDevices: onDevices,
          onDevicesChanged: onDevicesChanged,
         handlerType: runtimeType
      );

      if(Platform.isIOS){
        // 第一次时，主动开始，之后由生命周期决定，前台开始，非前台关闭
        _audioOutputDevice.startAudioRouteCheckTimer();
      }

    }

  }

  /// 音频设备组改变事件回调
  /// - 当监听到音频设备组改变时
  @mustCallSuper
  void onDevicesChanged(AudioDevicesChangedEvent event){}
  /// 音频设备组改变回调
  /// - 当监听到音频设备组改变时
  /// - 当回到 App 时，onResumed
  @mustCallSuper
  void onDevices(Set<AudioDevice> devices){
    _audioDevices = devices; // refresh
    if(Platform.isIOS){
      List<BleDevice> bleDevices = _audioDevices
          .where((e) => e.type.name.startsWith("bluetooth") && e.isInput)
          .map((e) => BleDevice.from(e)).toList();
      _a2dpDevices = bleDevices;
      Log.log('$runtimeType _a2dpDevices $_a2dpDevices');
      _headsetsController.add(
          _a2dpDevices
      );
    }else if(Platform.isAndroid){
      _refreshA2dpDevices();
    }
  }

  void setAudioRouteCheckGap({
    Duration duration = const Duration(seconds: 3)
  }){
    _audioOutputDevice.setAudioRouteCheckGap(duration);
  }

  /// check if certain address headset is connected
  bool isHeadsetConnected(String? address){
    if(address == null || address.isEmpty){
      return false;
    }
    Log.log('$runtimeType _a2dpDevices $_a2dpDevices');
    return _a2dpDevices.any(
            (e) => (e.address?.equals(address))??false
    );

  }

  String? getHeadsetNameWithAddress(String? address){
    if(address == null || address.isEmpty){
      return null;
    }
    return _a2dpDevices.firstWhereOrNull(
            (e) => (e.address?.equals(address))??false
    )?.name;
  }


  /// 经典蓝牙设备断开回调, 该方法目前只支持 Android
  /// - 当经典蓝牙设备断开时
  void _onClassicDeviceDisconnected(_){
    _refreshA2dpDevices();
  }

  void _refreshA2dpDevices(){
    _audioOutputDevice.getA2dpConnectedDevices().then((res){
      _setA2dpConnectedDevices(res);
    });
  }

  void _setA2dpConnectedDevices(List<BleDevice> devices){
    _a2dpDevices = devices;
    Log.log('$runtimeType _a2dpDevices $_a2dpDevices');
    _headsetsController.add(_a2dpDevices);
  }

  Future<void> closeAudioOutputDeviceHandler() async{
    // _hasInit = false; // should use some flag to avoid abuse
    await _classicDeviceDisconnectedSubs?.cancel();
    await _audioOutputDevice.close();
  }
}